package com.wuliang.blog.core.basic;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.wuliang.blog.response.Result;
import com.wuliang.blog.response.ResultUtil;
import com.wuliang.blog.response.ReturnCode;
import com.wuliang.blog.utils.JPAUtils;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 抽象出来的controller类，下列方法和接口可以选择性重写，或者是继续沿用
 *
 * @param <E> 因系统事务性的要求，所以此处的实体类对象应为controller对应的实体类对象
 * @author 胡明皓
 */
public abstract class BaseController<E extends BasicEntity, V extends BaseVo<E>> {

    /**
     * 此处声明基础Dao层的调用，仅作用与当前类
     */
    @Autowired(required = false)
    private BaseRepository<E> jpa;

    /**
     * @return 全部不分页数据
     */
    @GetMapping("/listAll")
    @ApiOperation(value = "全部不分页", response = Result.class)
    public Result<Object> listAll() {
        return ResultUtil.success(jpa.findAll());
    }

    /**
     * @param pageNo   当前页数
     * @param pageSize 每页显示的最大条目数
     * @return 全部分页数据
     */
    @PostMapping("/listAllByPage")
    @ApiOperation(value = "后台管理分页列表", response = Result.class)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "当前页数", name = "pageNo", dataType = "Number", paramType = "query"),
            @ApiImplicitParam(value = "每页显示条目数", name = "pageSize", dataType = "Number", paramType = "query")
    })
    public Result<Object> listAllByPage(@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
                                        @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        Page<E> entityOfPage = 
                jpa.findPageByDataStatus(0, PageRequest.of(pageNo - 1, pageSize, Sort.by("createTime").descending()));
        Map<String, Object> valueOfSendData = new LinkedHashMap<>();
        valueOfSendData.put("content", entityOfPage.getContent());
        valueOfSendData.put("totalElement", entityOfPage.getTotalElements());
        return ResultUtil.success(valueOfSendData);
    }

    /**
     * @param pageNo     当前页数
     * @param pageSize   每页显示的最大条目数
     * @param dataStatus 数据状态
     * @return 根据数据状态进行分页的数据
     */
    @PostMapping("/listByPageNo/{dataStatus}/{pageSize}/{pageNo}")
    @ApiOperation(value = "分页列表", response = Result.class)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "当前页数", name = "pageNo", dataType = "Number", paramType = "path"),
            @ApiImplicitParam(value = "每页显示条目数", name = "pageSize", dataType = "Number", paramType = "path"),
            @ApiImplicitParam(value = "数据状态", name = "dataStatus", dataType = "Number", paramType = "path")
    })
    public Result<Object> listByPageNo(@PathVariable(name = "pageNo") Integer pageNo,
                                       @PathVariable(name = "pageSize") Integer pageSize,
                                       @PathVariable(name = "dataStatus") Integer dataStatus) {
        return ResultUtil.success(jpa.findPageByDataStatus(dataStatus, PageRequest
                .of(pageNo - 1, pageSize, Sort.by("createTime").descending())).getContent());
    }

    /**
     * @param id    根据主键ID获取数据详情
     * @param token 当前登录的用户
     * @return 根据主机ID查询到的事务对象详情
     */
    @PostMapping("/getEntityById/{id}")
    @ApiOperation(value = "根据ID获取数据详情", response = Result.class)
    @ApiImplicitParam(value = "数据ID", name = "id", dataType = "number", paramType = "path")
    public Result<Object> getEntityById(@PathVariable(name = "id") Integer id, @RequestHeader("Token") String token) {
        Optional<E> entityOptional = jpa.findById(id);
        return entityOptional.map(ResultUtil::success).orElseGet(ResultUtil::dataEmptyError);
    }

    /**
     * @param id 主机ID
     * @return 根据主键ID
     */
    @PostMapping("/deleteOne/{id}")
    @ApiOperation(value = "删除单条数据", response = Result.class)
    @ApiImplicitParam(value = "数据ID", name = "id", dataType = "String", paramType = "path")
    public Result<Object> deleteOne(@PathVariable("id") Integer id) {
        if (StringUtils.isEmpty(id)) {
            return ResultUtil.error(ReturnCode.PARAM_NOT_FOUND);
        }
        Optional<E> entityOptional = jpa.findById(id);
        if (!entityOptional.isPresent()) {
            return ResultUtil.dataEmptyError();
        }
        E entity = entityOptional.get();
        entity.setDataStatus(1);
        jpa.save(entity);
        return ResultUtil.success();
    }

    @PostMapping("/deleteOneByUser/{id}")
    @ApiOperation(value = "删除单条数据", response = Result.class)
    @ApiImplicitParams({
            @ApiImplicitParam(value = "数据ID", name = "id", dataType = "String", paramType = "path"),
            @ApiImplicitParam(name = "Token", value = "Token", dataType = "string", paramType = " header")
    })
    public Result<Object> deleteOne(@PathVariable Integer id, @RequestHeader("Token") String token) throws IOException {
        return deleteOne(id);
    }

    /**
     * 根据主键ID数组进行删除
     *
     * @param receiveData 请求对象
     * @return 是否删除成功
     */
    @PostMapping("/deleteByIdList")
    @ApiOperation(value = "批量删除", response = Result.class)
    @ApiImplicitParam(value = "被选中的数据ID数组", name = "ids", dataType = "String", paramType = "param", example = "\"[1, 2, 3, 4, 5]\"")
    public Result<Object> deleteByIdList(@RequestBody Map<String, Object> receiveData) {
        String ids = receiveData.get("ids").toString();
        List<E> entityList = new ArrayList<>();
        try {
            List<Integer> idList = new Gson().fromJson(ids, List.class);
            idList.forEach(id -> {
                Optional<E> entityOptional = jpa.findById(id);
                if (!entityOptional.isPresent()) {
                    return;
                }
                E entity = entityOptional.get();
                entity.setDataStatus(1);
                entityList.add(entity);
            });
            if (entityList.size() != idList.size()) {
                return ResultUtil.error("批量删除失败!", ReturnCode.ERROR);
            }
            jpa.saveAll(entityList);
        } catch (JsonSyntaxException e) {
            return ResultUtil.systemError(e.getMessage());
        } catch (Exception e) {
            return ResultUtil.error(ReturnCode.SYSTEM_EXCEPTION);
        }

        return ResultUtil.success();
    }

    @PostMapping("/findPageBySomeField/{pageSize}/{pageNo}")
    @ApiOperation(value = "根据关键字罗列分页列表")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "分页的数量", name = "pageSize", dataType = "int", paramType = "path"),
            @ApiImplicitParam(value = "当前页数", name = "pageNo", dataType = "int", paramType = "path"),
            @ApiImplicitParam(value = "其他字段", dataType = "object", paramType = "body")
    })
    public Result<Object> findPageBySomeField(V vo, @PathVariable("pageSize") Integer pageSize,
                                              @PathVariable("pageNo") Integer pageNo) {
        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by("createTime").descending());
        return ResultUtil.success(jpa.findAll(vo.toSpecification(), pageable));
    }

    public abstract Result<Object> save(@RequestBody V vo);
}
